Best Practice

Helper Utilities

Testplan provides helper functions and a predefined testsuite that make it easy for the user to add common testplan execution infomation - such as env var, pwd, log file, driver metadata - to the test report.

DriverLogCollector

You can specify your custom log collector using DriverLogCollector. It will attach the specified log files to the report for each driver. Example:

from testplan.common.utils import helper

log_collector = helper.DriverLogCollector(
    name="custom_log_collector",
    file_pattern=["*.log"],
    description="Driver log files",
    ignore="not_important.log",
    recursive=True,
    failure_only=False,
)
log_collector(env, result)
Required files:

test_plan.py

#!/usr/bin/env python
"""
Example demonstrating usage of testplan.common.utils.helper module.
By using the helper functions and/or the prefedined Testsuite, the user can
readily add additional information of Testplan execution to the report.
"""

import sys
from testplan import test_plan
from testplan.testing.multitest import MultiTest, testsuite, testcase
from testplan.testing.multitest.driver.app import App
from testplan.common.utils import helper


@testsuite
class MyTestsuite:
    """
    A testsuite that uses helper utilities in setup/teardown.
    """

    def setup(self, env, result):
        # Save host environment variable in report.
        helper.log_environment(result)

        # Save current path & command line arguments in report.
        helper.log_pwd(result)
        helper.log_cmd(result)

        # Save host hardware information in report.
        helper.log_hardware(result)

    @testcase
    def my_testcase(self, env, result):
        # Add your testcase here
        result.true(True)

    def teardown(self, env, result):
        """
        Attach testplan.log file in report.
        """
        helper.attach_log(result)


def before_start_fn(env, result):
    # Save host environment variable in report.
    helper.log_environment(result)

    # Save current path & command line arguments in report.
    helper.log_pwd(result)


def after_stop_fn(env, result):
    # Attach drivers' log files if the multitest failed.
    stdout_logger = helper.DriverLogCollector(
        file_pattern=["stdout*"], description="stdout"
    )
    stderr_logger = helper.DriverLogCollector(
        file_pattern=["stderr*"], description="stderr"
    )

    stdout_logger(env, result)
    stderr_logger(env, result)

    # Delete Multitest level runpath if the multitest passed.
    # This function cleans the the runpath before the exporters
    # have chance collecting the files, hence commented out.
    # helper.clean_runpath_if_passed(env, result)


@test_plan(name="Example using helper")
def main(plan):
    """
    Add a MultiTest that uses helper utilities in before_start/after_stop hooks.
    """
    plan.add(
        MultiTest(
            name="HelperTest",
            suites=[
                # This is a pre-defined testsuite that logs info to report
                helper.TestplanExecutionInfo(),
                MyTestsuite(),
            ],  # shortcut: suites=[helper.TestplanExecutionInfo()]
            environment=[App("echo", binary="/bin/echo", args=["testplan"])],
            before_start=before_start_fn,
            after_stop=after_stop_fn,
        )
    )


if __name__ == "__main__":
    sys.exit(main().exit_code)
Required files:

test_plan_metadata.py

#!/usr/bin/env python
"""
Example demonstrating the usage of on-demand Driver metadata
extraction.
"""
import sys

from testplan import test_plan
from testplan.common.utils import helper
from testplan.common.utils.context import context
from testplan.testing.multitest import MultiTest, testsuite, testcase
from testplan.testing.multitest.driver.base import (
    Direction,
    Connection,
    DriverMetadata,
)
from testplan.testing.multitest.driver.tcp import TCPServer, TCPClient


def before_start(env, result):
    """
    Extracts driver metadata before environment startup.
    """
    helper.extract_driver_metadata(env, result)


def after_start(env, result):
    """
    Accepts TCPClient connection on TCPServer side and extracts driver
    metadata after startup.
    """
    env.server.accept_connection()
    helper.extract_driver_metadata(env, result)


def metadata_extractor_server(driver: TCPServer) -> DriverMetadata:
    """
    TCPServer specific metadata extractor function.

    :param driver: TCPServer driver instance
    :return: driver name, driver class, host, and connecting port metadata
    """
    return DriverMetadata(
        name=driver.name,
        driver_metadata={
            "class": driver.__class__.__name__,
            "host": driver.host or driver.cfg.host,
        },
        conn_info=[
            Connection(
                name="data_port",
                protocol="TCP",
                identifier=driver.port or driver.cfg.port,
                direction=Direction.listening,
            )
        ],
    )


def metadata_extractor_client(driver: TCPClient) -> DriverMetadata:
    """
    TCPClient specific metadata extractor function.

    :param driver: TCPClient driver instance
    :return: driver name, driver class, host, and connecting port metadata
    """
    return DriverMetadata(
        name=driver.name,
        driver_metadata={
            "class": driver.__class__.__name__,
            "host": driver.host or driver.cfg.host,
        },
        conn_info=[
            Connection(
                name="to_server",
                protocol="TCP",
                identifier=driver.server_port or driver.cfg.port,
                direction=Direction.connecting,
            )
        ],
    )


@testsuite
class TCPSuite:
    @testcase
    def test_send_msg(self, env, result):
        """
        Simple testcase sending a message from client to server side at which it
        is received and the integrity is tested.
        """
        msg = "Hello Server!"
        msg_sent = env.client.send_text(msg)
        msg_received = env.server.receive_text(size=msg_sent)
        result.equal(msg_received, msg, "Message received on server side")


@test_plan(name="Example of Driver metadata extraction")
def main(plan):
    plan.add(
        MultiTest(
            name="Metadata extraction",
            suites=[TCPSuite()],
            environment=[
                TCPServer(
                    name="server",
                    metadata_extractor=metadata_extractor_server,
                ),
                TCPClient(
                    name="client",
                    host=context("server", "{{host}}"),
                    port=context("server", "{{port}}"),
                    metadata_extractor=metadata_extractor_client,
                ),
            ],
            before_start=before_start,
            after_start=after_start,
        )
    )


if __name__ == "__main__":
    sys.exit(not main())